use axum::{
    Router,
    extract::{Path, State},
    http::StatusCode,
    response::Json,
    routing::{delete, get, post, put},
};
use chrono::Utc;
use serde::Serialize;
use diesel::prelude::*;
use diesel::r2d2::{self, ConnectionManager};
use uuid::Uuid;
use tower::ServiceBuilder;
use tower_http::cors::CorsLayer;

mod schema;
mod models;

use models::*;
use schema::users;

type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;

#[derive(Serialize)]
struct ApiResponse<T> {
    success: bool,
    data: Option<T>,
    message: String,
}

impl<T> ApiResponse<T> {
    fn success(data: T, message: &str) -> Self {
        Self {
            success: true,
            data: Some(data),
            message: message.to_string(),
        }
    }

    fn error(message: &str) -> Self {
        Self {
            success: false,
            data: None,
            message: message.to_string(),
        }
    }
}

async fn health() -> Json<ApiResponse<String>> {
    Json(ApiResponse::success("OK".to_string(), "Server is healthy"))
}

async fn get_users(
    State(pool): State<DbPool>,
) -> Result<Json<ApiResponse<Vec<User>>>, StatusCode> {
    let mut conn = pool.get().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    let users_result = users::table
        .order(users::created_at.desc())
        .load::<User>(&mut conn);

    match users_result {
        Ok(users) => Ok(Json(ApiResponse::success(
            users,
            "Users retrieved successfully",
        ))),
        Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
    }
}

async fn get_user(
    Path(user_id): Path<Uuid>,
    State(pool): State<DbPool>,
) -> Result<Json<ApiResponse<User>>, StatusCode> {
    let mut conn = pool.get().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    let user = users::table
        .find(user_id)
        .first::<User>(&mut conn)
        .map_err(|_| StatusCode::NOT_FOUND)?;

    Ok(Json(ApiResponse::success(user, "User found")))
}

async fn create_user(
    State(pool): State<DbPool>,
    Json(payload): Json<CreateUserRequest>,
) -> Result<Json<ApiResponse<User>>, StatusCode> {
    let mut conn = pool.get().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    let new_user = NewUser {
        id: Uuid::new_v4(),
        name: payload.name,
        email: payload.email,
        age: payload.age,
        created_at: Utc::now(),
        updated_at: Utc::now(),
    };

    let user = diesel::insert_into(users::table)
        .values(&new_user)
        .returning(User::as_returning())
        .get_result(&mut conn)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok(Json(ApiResponse::success(
        user,
        "User created successfully",
    )))
}

async fn update_user(
    Path(user_id): Path<Uuid>,
    State(pool): State<DbPool>,
    Json(payload): Json<UpdateUserRequest>,
) -> Result<Json<ApiResponse<User>>, StatusCode> {
    let mut conn = pool.get().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // 检查用户是否存在
    let existing_user = users::table
        .find(&user_id)
        .first::<User>(&mut conn)
        .map_err(|_| StatusCode::NOT_FOUND)?;

    // 使用新值或保持原值
    let name = payload.name.unwrap_or(existing_user.name);
    let email = payload.email.unwrap_or(existing_user.email);
    let age = payload.age.or(existing_user.age);

    let updated_user = diesel::update(users::table.find(&user_id))
        .set((
            users::name.eq(&name),
            users::email.eq(&email),
            users::age.eq(&age),
            users::updated_at.eq(Utc::now()),
        ))
        .returning(User::as_returning())
        .get_result(&mut conn)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok(Json(ApiResponse::success(
        updated_user,
        "User updated successfully",
    )))
}

async fn delete_user(
    Path(user_id): Path<Uuid>,
    State(pool): State<DbPool>,
) -> Result<Json<ApiResponse<String>>, StatusCode> {
    let mut conn = pool.get().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    let deleted_count = diesel::delete(users::table.find(&user_id))
        .execute(&mut conn)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    if deleted_count == 0 {
        return Err(StatusCode::NOT_FOUND);
    }

    Ok(Json(ApiResponse::success(
        user_id.to_string(),
        "User deleted successfully",
    )))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 加载环境变量
    dotenvy::dotenv().ok();

    // 创建数据库连接池
    let database_url = std::env::var("DATABASE_URL")
        .unwrap_or_else(|_| "postgresql://postgres:123456@localhost:5432/postgres".to_string());

    let manager = ConnectionManager::<PgConnection>::new(&database_url);
    let pool = r2d2::Pool::builder()
        .max_size(10)
        .build(manager)
        .expect("Failed to create pool");

    // 构建应用路由
    let app = Router::new()
        .route("/health", get(health))
        .route("/users", get(get_users))
        .route("/users", post(create_user))
        .route("/users/{id}", get(get_user))
        .route("/users/{id}", put(update_user))
        .route("/users/{id}", delete(delete_user))
        .layer(ServiceBuilder::new().layer(CorsLayer::permissive()))
        .with_state(pool);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3002")
        .await
        .expect("Failed to bind to port 3002");

    println!("📋 Available endpoints:");
    println!("  GET    /health         - Health check");
    println!("  GET    /users          - Get all users");
    println!("  POST   /users          - Create new user");
    println!("  GET    /users/{{id}}     - Get user by ID");
    println!("  PUT    /users/{{id}}     - Update user by ID");
    println!("  DELETE /users/{{id}}     - Delete user by ID");
    println!("📄 Database: PostgreSQL ({})", database_url);

    println!("🚀 Diesel + Axum Server running on http://localhost:3002");

    axum::serve(listener, app)
        .await
        .expect("Failed to start server");

    Ok(())
}